﻿using Nest;
using PMS.Search.Domain.Entities;
using PMS.Search.Elasticsearch;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ElasticSearchTest
{
    public class SchoolEsService
    {
        private readonly EsClient _client;
        private readonly EsIndexConfig.Index _index = EsIndexConfig.Instance.SchoolIndex;

        public SchoolEsService(EsClient client)
        {
            _client = client;
        }

        public CreateIndexResponse CreateIndex()
        {
            var resp = _client.GetClient().Indices.Delete(_index.Name);
            var createIndexResponse = _client.GetClient().Indices.Create(_index.Name, c => c
                .Aliases(ad => ad.Alias(_index.Alias))
                .Settings(s => s
                    .Setting("max_ngram_diff", 20)
                    .Setting("max_result_window", 500000)
                    .Analysis(a => a
                        .CharFilters(cf => cf
                           .UserDefined("tsconvert", new TSConvertCharFilter("t2s", "#"))
                         )
                        .TokenFilters(tf => tf
                            .UserDefined("pinyin_max_filter",
                                //取首字母缩写，拼音全连接，每个字拼音，保留原输入，小写的非中文字母，删除重复项
                                new PinyinTokenFilter
                                {
                                    KeepSeparateFirstLetter = false,
                                    KeepJoinedFullPinyin = true,
                                    KeepFullPinyin = true,
                                    KeepOriginal = true,
                                    LimitFirstLetterLength = 16,
                                    Lowercase = true,
                                    RemoveDuplicatedTerm = true
                                })
                            .UserDefined("pinyin_keyword_filter",
                                //取首字母缩写，拼音全连接，保留原输入，小写的非中文字母，删除重复项
                                new PinyinTokenFilter
                                {
                                    KeepFirstLetter = true,
                                    KeepSeparateFirstLetter = false,
                                    KeepJoinedFullPinyin = true,
                                    KeepFullPinyin = false,
                                    KeepOriginal = true,
                                    LimitFirstLetterLength = 16,
                                    Lowercase = true,
                                    RemoveDuplicatedTerm = true
                                })
                            .UserDefined("pinyin_only_filter",
                                //取首字母缩写，拼音全连接，不保留原输入，小写的非中文字母，删除重复项
                                new PinyinTokenFilter
                                {
                                    KeepFirstLetter = true,
                                    KeepSeparateFirstLetter = false,
                                    KeepJoinedFullPinyin = true,
                                    KeepFullPinyin = false,
                                    KeepOriginal = false,
                                    LimitFirstLetterLength = 16,
                                    Lowercase = true,
                                    RemoveDuplicatedTerm = true
                                })
                            .UserDefined("pinyin_filter",
                                //取首字母缩写，拼音全连接，保留原输入，小写的非中文字母，删除重复项
                                new PinyinTokenFilter
                                {
                                    KeepFirstLetter = true,
                                    KeepNoneChineseTogether = true,
                                    KeepSeparateFirstLetter = false,
                                    KeepJoinedFullPinyin = true,
                                    KeepFullPinyin = false,
                                    KeepOriginal = true,
                                    LimitFirstLetterLength = 16,
                                    Lowercase = true,
                                    RemoveDuplicatedTerm = true
                                })
                            .EdgeNGram("edge_ngram_filter",
                                etf => etf.MinGram(1).MaxGram(50)
                            )
                            .NGram("ngram_filter",
                                etf => etf.MinGram(1).MaxGram(2)
                            )
                        )
                        .Tokenizers(t => t.EdgeNGram("ngram_tokenizer", nt => nt
                               .MinGram(1).MaxGram(6)
                               .TokenChars(TokenChar.Letter, TokenChar.Digit)
                            )
                        )
                        .Analyzers(aa => aa
                            //不分词，仅转小写
                            .Custom("string_lowercase", ca => ca
                                 .Tokenizer("keyword")
                                 .Filters("lowercase")
                             )
                            .Custom("ik_analyzer", ca => ca
                                 .CharFilters("tsconvert")
                                 .Tokenizer("ik_max_word")
                                 .Filters("ngram_filter", "lowercase")
                             )
                            .Custom("ik_search_analyzer", ca => ca
                                 .CharFilters("tsconvert")
                                 .Tokenizer("ik_smart")
                                 .Filters("lowercase")
                             )
                            .Custom("ik_pinyin_analyzer", ca => ca
                                 .CharFilters("tsconvert")
                                 .Tokenizer("ik_max_word")
                                 .Filters("edge_ngram_filter", "pinyin_filter", "lowercase")
                             )
                            .Custom("ik_pinyin_only_analyzer", ca => ca
                                 .CharFilters("tsconvert")
                                 .Tokenizer("ik_max_word")
                                 .Filters("pinyin_only_filter", "edge_ngram_filter", "lowercase")
                             )
                            .Custom("ik_pinyin_search_analyzer", ca => ca
                                 .CharFilters("tsconvert")
                                 .Tokenizer("ik_smart")
                                 .Filters("pinyin_filter", "lowercase")
                             )
                            .Custom("ngram_analyzer", ca => ca
                                 .CharFilters("tsconvert")
                                 .Tokenizer("ngram_tokenizer")
                                 .Filters("lowercase")
                             )
                            .Custom("ngram_pinyin_analyzer", ca => ca
                                 .CharFilters("tsconvert")
                                 .Tokenizer("ngram_tokenizer")
                                 .Filters("pinyin_filter", "lowercase")
                             )
                            //不分词，转拼音，EdgeNgram分割
                            .Custom("keyword_pinyin_ngram_analyzer", ca => ca
                                 .CharFilters("tsconvert")
                                 .Tokenizer("keyword")
                                 .Filters("pinyin_filter", "edge_ngram_filter", "lowercase")
                             )
                            //不分词，转小写，繁转中
                            .Custom("keyword_search_analyzer", ca => ca
                                 .CharFilters("tsconvert")
                                 .Tokenizer("keyword")
                                 .Filters("lowercase")
                             )
                            //不分词，转拼音，拼音首字母
                            .Custom("keyword_pinyin_search_analyzer", ca => ca
                                 .CharFilters("tsconvert")
                                 .Tokenizer("keyword")
                                 .Filters("pinyin_keyword_filter", "edge_ngram_filter", "lowercase")
                             )
                        )
                ))
                .Map<SearchSchool>(mm => mm
                .Properties(p => p
                        .Keyword(t => t
                            .Name(n => n.Id)
                        )
                        .Keyword(t => t
                            .Name(n => n.SchoolId)
                        )
                        .Text(t => t
                            .Name(n => n.Name)
                            .Fields(f => f
                                .Text(ft
                                    => ft.Name("cntext")
                                    .Store(false)
                                    //.TermVector(TermVectorOption.WithPositionsOffsets)
                                    .Analyzer("ik_analyzer")
                                    .SearchAnalyzer("ik_search_analyzer"))
                                .Text(ft
                                    => ft.Name("pinyin")
                                    .Store(false)
                                    //.TermVector(TermVectorOption.WithPositionsOffsets)
                                    .Analyzer("ik_pinyin_only_analyzer")
                                    .SearchAnalyzer("ik_search_analyzer"))
                                .Text(ft
                                    => ft.Name("keyword")
                                    .Store(false)
                                    //.TermVector(TermVectorOption.WithPositionsOffsets)
                                    .Analyzer("keyword_pinyin_ngram_analyzer")
                                    .SearchAnalyzer("ik_search_analyzer"))
                            )
                        )
                        .GeoPoint(t => t
                            .Name(n => n.Location)
                        )
                        .Text(t => t
                            .Name(n => n.City)
                        //.CopyTo(ct => ct.Field(ff => ff.Cityarea))
                        )
                        .Text(t => t
                            .Name(n => n.Area)
                        //.CopyTo(ct => ct.Field(ff => ff.Cityarea))
                        )
                        .Number(t => t.Name(n => n.CityCode))
                        .Number(t => t.Name(n => n.AreaCode))
                        .Text(t => t
                            .Name(n => n.Cityarea)
                            //.Store(true)
                            .Fields(f => f
                                .Text(ft
                                  => ft.Name("pinyin")
                                  .Store(false)
                                  .Analyzer("ik_pinyin_analyzer")
                                  .SearchAnalyzer("ik_search_analyzer")
                                  )
                                  .Text(ft
                                  => ft.Name("cntext")
                                  .Store(false)
                                  .Analyzer("ik_analyzer")
                                  .SearchAnalyzer("ik_search_analyzer")
                                )
                            )
                        )
                        .Number(t => t.Name(n => n.Grade))
                        .Text(t => t
                            .Name(n => n.Schooltype)
                            .Fields(f => f.Text(ft
                                  => ft.Name("pinyin")
                                  .Store(false)
                                  .Analyzer("ik_pinyin_analyzer")
                                  .SearchAnalyzer("ik_search_analyzer")
                                  )
                                  .Text(ft
                                  => ft.Name("cntext")
                                  .Store(false)
                                  .Analyzer("ik_analyzer")
                                  .SearchAnalyzer("ik_search_analyzer")
                                )
                            )
                        )
                        .Keyword(t => t
                            .Name(n => n.SchooltypeCode)
                        )
                        .Keyword(t => t
                            .Name(n => n.MetroLineId).Fields(ff => ff.Keyword(fk => fk.Name("keyword")))
                        )
                        .Keyword(t => t.Name(n => n.MetroStationId).Fields(ff => ff.Number(fk => fk.Name("keyword"))))
                        .Boolean(t => t.Name(n => n.Canteen))
                        .Boolean(t => t.Name(n => n.Lodging))
                        .Number(t => t.Name(n => n.Studentcount))
                        .Number(t => t.Name(n => n.Teachercount))
                        .Number(t => t.Name(n => n.Star))
                        .Number(t => t.Name(n => n.Commentcount))
                        .Number(t => t.Name(n => n.Questioncount))
                        .Object<SearchSchoolScore>(t => t.Name(n => n.Score)
                            .Properties(pp => pp.Number(fk => fk.Name(n => n.Total))
                                            .Number(fk => fk.Name(n => n.Composite))
                                            .Number(fk => fk.Name(n => n.Cost))
                                            .Number(fk => fk.Name(n => n.Course))
                                            .Number(fk => fk.Name(n => n.Hard))
                                            .Number(fk => fk.Name(n => n.Learn))
                                            .Number(fk => fk.Name(n => n.Teach))
                                            .Number(fk => fk.Name(n => n.Envir))
                            )
                        )
                        .Keyword(t => t.Name(n => n.Authentication).Fields(ff => ff.Keyword(fk => fk.Name("keyword"))))
                        .Keyword(t => t.Name(n => n.Characteristic).Fields(ff => ff.Keyword(fk => fk.Name("keyword"))))
                        .Keyword(t => t.Name(n => n.Abroad).Fields(ff => ff.Keyword(fk => fk.Name("keyword"))))
                        .Keyword(t => t.Name(n => n.Courses).Fields(ff => ff.Keyword(fk => fk.Name("keyword"))))
                        .Text(t => t.Name(n => n.Tags)
                            .Fields(ff => ff
                                .Text(fk => fk.Name("keyword").Analyzer("string_lowercase").SearchAnalyzer("keyword_search_analyzer"))
                                .Text(fk => fk.Name("pinyin").Analyzer("ik_pinyin_analyzer").SearchAnalyzer("ik_search_analyzer"))
                                .Text(fk => fk.Name("cntext").Analyzer("ik_analyzer").SearchAnalyzer("ik_search_analyzer"))
                            )
                        )
                        .Number(t => t.Name(n => n.Tuition))
                        .Date(t => t.Name(n => n.UpdateTime))
                        .Boolean(t => t.Name(n => n.IsDeleted))
                        .Number(t => t.Name(n => n.ViewCount))
                        .Number(t => t.Name(n => n.HotValue))
                        .Number(t => t.Name(n => n.Pv))
                        .Number(t => t.Name(n => n.Uv))
                    ))
            );
            return createIndexResponse;
        }
    }
}
